[Android] surfaceview之MemoryTable动态内存显示表

surfaceView系列03

Posted by Aerber Zhou on 2017-05-18

一.变量和方法

变量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//刷新频率
public int frequency = 8;

//内存表上的最大时间
public float time = 60;

//单位数据宽度
private float pwidth;

private Thread thread;

private SurfaceHolder holder;

private Paint paint;

private Shader shader;

//在60s内所有的数据记录
private List<Double> values;

方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public MemoryTable(Context context) {  }

public MemoryTable(Context context, AttributeSet attrs) { }

public MemoryTable(Context context, AttributeSet attrs, int defStyleAttr) { }

private void init() { }

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {}

private void mDraw() { }

//给memorytable中添加数据
public void addValue(double value) {}

//把y值转化成在内存表内的高度
private float valueToHeight(float height,double value) { }

二.构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public MemoryTable(Context context) {
super(context);
init();
}

public MemoryTable(Context context, AttributeSet attrs) {
super(context,attrs);
init();
}

public MemoryTable(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}

三.private void init(){}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
private void init() {
//实例化
values = new ArrayList<Double>();
paint = new Paint();
paint.setAntiAlias(true);
paint.setPathEffect(new CornerPathEffect(pwidth));

holder = this.getHolder();
holder.addCallback(new SurfaceHolder.Callback() {

public void surfaceCreated(SurfaceHolder holder) {
thread = new Thread( new Runnable() {

public void run() {
while(true) {
try {
mDraw();
Thread.sleep(80);
} catch (InterruptedException e) {

}
}
}
});
thread.start();
}

public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

}

public void surfaceDestroyed(SurfaceHolder holder) {
thread.interrupt();
thread = null;
}
});
}

四.protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//单位数据宽度的逻辑计算方法
pwidth = (MeasureSpec.getSize(widthMeasureSpec) - 65) / time / frequency;
//设置LinearGradient线性渐变
//http://www.cnblogs.com/menlsh/archive/2012/12/09/2810372.html
//参数一为渐变起初点坐标x位置,参数二为y轴位置,参数三和四分辨对应渐变终点x,y
//其中参数new int[]{}是参与渐变效果的颜色集合,
//其中参数new float[]{}是定义每个颜色处于的渐变相对位置,
// 这个参数可以为null,如果为null表示所有的颜色按顺序均匀的分布
//其中参数Shader.TileMode.REPEAT可以理解为多个充分,这个可以看一下API文档
//CLAMP
// replicate the edge color if the shader draws outside of its original bounds
//MIRROR
// repeat the shader's image horizontally and vertically, alternating mirror images so that adjacent images always seam
//REPEAT
// repeat the shader's image horizontally and vertically
shader = new LinearGradient(0,0,0,MeasureSpec.getSize(heightMeasureSpec) - 40,
new int[]{getResources().getColor(R.color.memorytable_third),getResources().getColor(R.color.memorytable_sec),getResources().getColor(R.color.memorytable_first)},
new float[]{0f,0.4f,1f}, Shader.TileMode.REPEAT);
super.onMeasure(widthMeasureSpec,heightMeasureSpec);
}

五.private void mDraw() {}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
private void mDraw() {
Canvas c = null;
try {
c = holder.lockCanvas();
if(c == null) return;
c.drawColor(Color.WHITE);
c.translate(30,10);
paint.setAlpha(255);
paint.setColor(Color.BLACK);
//内存表的长和宽
int width = getWidth() - 65;
int height = getHeight() - 40;
//draw edges
//绘制X,Y轴的分度,把大表格分成小格子
for(int i = 0; i < 7; i ++)
//Y轴
c.drawLine(width / 6f * i,0,width / 6f * i,height,paint);
for(int i = 0; i < 6; i ++)
//X轴
c.drawLine(0,height / 5f * i,width,height / 5f * i,paint);
//draw text
//绘制XY轴每个分度上的数字
//居中对齐
paint.setTextAlign(Paint.Align.CENTER);
for(int i = 0; i < 7; i ++)
//X轴
c.drawText((6-i) + (i==6?"":"0") + (i==0?"seconds":""),width / 6f * i,height+20,paint);
//左对齐
paint.setTextAlign(Paint.Align.LEFT);
for(int i = 0; i < 6; i ++)
//Y轴
c.drawText(2*(5-i) + (i==5?"":"0") + "%",width+5,height / 5f * i,paint);
float cy = width;
Path path = new Path();
//以右下角为零点,作为内存变化曲线图的起点
path.moveTo(cy,height);


//lineto
//绘制values中的所有的点,连成为线
for(double value : values) {
//绘制顺序是时间由近到远,即先绘制新数据,后绘制旧数据,由右往左绘制
//使用数据时是栈思想
path.lineTo(cy,valueToHeight(height,value));
//由于画布的原点是左上角,所以x越小越左
//每次减少一个分度
cy -= pwidth;
}
//在绘制了最旧的数据后,垂直向下到到x轴上
path.lineTo(cy+pwidth,height);
//返回原点
path.lineTo(width,height);
paint.setShader(shader);
c.drawPath(path,paint);
paint.setShader(null);
} catch (Exception e) {

} finally {
if(c != null)
holder.unlockCanvasAndPost(c);
}

}

六.public void addValue(double value) {}

1
2
3
4
5
6
7
8
9
10
    public void addValue(double value) {
if(values == null) throw new NullPointerException("The values is null!");
//如果当数据已经满屏
//添加数据时是队列思想
if(values.size() > time * frequency)
//把数据数组中的最后一个删除
values.remove(values.size()-1);
//把最新的数据添加到数组的第一项
values.add(0, value);
}

七.private float valueToHeight(float height,double value) {}

1
2
3
4
5
//把y值转化成在内存表内的高度
//由于画布的原点是左上角,所以y越小越高
private float valueToHeight(float height,double value) {
return (float)(height *(1 - value));
}